#include "TitleScreenState.h"
#include "ScreenManager.h"
#include "Game.h"
#include "DX11HelpfulFunctions.h"
#include "TestState.h"
#include "Text.h"
#include "DX11TextureManager.h"
#include "Timer.h"
#include "LoadGameObjects.h"
#include "ConfigManager.h"
#include "MiniMap.h"
#include "InfoState.h"

#include <AcceptConThread.h>
#include <ClientSocket.h>
#include <SocketMessage.h>
#include <GMCreatePlayer.h>
#include <SendGameMessage.h>
#include <MessageRecvThread.h>
#include <CheckPingThread.h>
#include <ClientManager.h>
#include <TimerMS.h>

TitleScreenState::TitleScreenState()
{
	m_screenSize.x = (float)TheScreenManager::Instance()->GetWindowWidth();
	m_screenSize.y = (float)TheScreenManager::Instance()->GetWindowHeight();
	m_mouseDown = false;
	m_curState = MAIN;
	m_canEditPort = false;
	m_canEditServer = false;
	m_spacing = TheFontManager::Instance()->GetSpacing("eras");
	m_serverText = "Server IP:";
	m_portText = "Port:";
	m_serverIP = "localhost";
	m_port = "40001";
}

void TitleScreenState::Draw()
{
	DX11::ClearColour(0.0f, 0.0f, 0.0f, 1.0f);

	D3DXMATRIX m_view;
	D3DXMATRIX m_proj;

	D3DXMatrixLookAtLH(&m_view, &D3DXVECTOR3(0.0f, 0.0f, 1.0f), 
		&D3DXVECTOR3(0.0f, 0.0f, 0.0f), 
		&D3DXVECTOR3(0.0f, 1.0f, 0.0f));

	D3DXMatrixOrthoLH(&m_proj, m_screenSize.x, m_screenSize.y, 0, 100);

	TheScreenManager::Instance()->SetViewProjMatrix(m_view, m_proj);

	TheScreenManager::Instance()->EnableBlending();
	TheObjMeshManager::Instance()->ChangeTexture("title_quad",
		TheDX11TextureManager::Instance()->UseTexture(L"../../Assets/title_image.png"));
	//TheObjMeshManager::Instance()->Translate("title_quad", D3DXVECTOR3(0.0f, -1.0f, rot));
	TheObjMeshManager::Instance()->Scale("title_quad", D3DXVECTOR3(m_screenSize.x, m_screenSize.y, 1.0f));
	//TheObjMeshManager::Instance()->Rotate("title_quad", M_PI_4, 1.0f, 0.0f, 0.0f);
	TheObjMeshManager::Instance()->Draw("title_quad");
	TheScreenManager::Instance()->DisableBlending();


	m_col = D3DXVECTOR4(0.0f, 1.0f, 0.89411f, 1.0f);
	static float a = 0.0f;
	a += 2.0f * TheTimer::Instance()->GetDt();
	m_alpha = sin(a) + 1.0f;
	m_alpha *= 0.4f;
	if (m_curState == MAIN)
	{
		m_text.SetColour(D3DXVECTOR4(m_col.x, m_col.y, m_col.z, m_alpha));
		// server button
		m_text.Update("Host and Play");
		m_text.Translate(D3DXVECTOR3(0.0f, 0.3f, 0.0f));
		m_text.Draw();

		if (m_text.Intersected(m_convertedMousePos))
		{
			m_text.SetColour(D3DXVECTOR4(m_col.x, m_col.y, m_col.z, 0.0f));
			m_text.Update("<               >");
			m_text.Draw();
			if (m_mouseDown)
			{
				// call server function
				m_port = "";
				m_curState = HOST_AND_PLAY;
				m_mouseDown = false;
			}
		}

		// client button
		m_text.Update("Join");
		m_text.Translate(D3DXVECTOR3(0.0f, 0.1f, 0.0f));
		m_text.SetColour(D3DXVECTOR4(m_col.x, m_col.y, m_col.z, m_alpha));
		m_text.Draw();

		if (m_text.Intersected(m_convertedMousePos))
		{
			m_text.SetColour(D3DXVECTOR4(m_col.x, m_col.y, m_col.z, 0.0f));
			m_text.Update("<      >");
			m_text.Draw();
			if (m_mouseDown)
			{
				// call Join function
				m_port = "";
				m_serverIP = "";
				m_curState = JOIN;
				m_mouseDown = false;
			}
		}

		// exit button
		m_text.Update("Exit");
		m_text.Translate(D3DXVECTOR3(0.0f, -0.1f, 0.0f));
		m_text.SetColour(D3DXVECTOR4(m_col.x, m_col.y, m_col.z, m_alpha));
		m_text.Draw();

		if (m_text.Intersected(m_convertedMousePos))
		{
			m_text.SetColour(D3DXVECTOR4(m_col.x, m_col.y, m_col.z, 0.0f));
			m_text.Update("<      >");
			m_text.Draw();
			if (m_mouseDown)
			{
				PostQuitMessage(0);
			}
		}
	}
	else if (m_curState == HOST_AND_PLAY)
	{
		HostAndPlay();
	}
	else if (m_curState == JOIN)
	{
		Join();
	}
	else if (m_curState == EXIT)
	{

	}
	else if (m_curState == CONNECTING_TO_SERVER)
	{
		ConnectToServer();
	}
	else if (m_curState == CREATING_SERVER)
	{
		CreateServer();
	}



	//if (m_mouseDown)
	//{	
	//	t.Update("Generating maze. . .");
	//	t.Translate(D3DXVECTOR3(0.0f, 0.0f, 0.0));
	//	t.SetColour(D3DXVECTOR4(0.0f, 1.0f, 0.89411f, 0.0f));
	//	t.Draw();

	//	TheScreenManager::Instance()->FlipBuffers();
	//	
	//	TheConfigManager::Instance()->Load("../../Config/config.info");
	//	LoadGameObjects(L"../../Game_Objects/test_gameobjects.txt");
	//	TheMiniMap::Instance()->Reset();
	//	TheGame::Instance()->SetGameState(TheTestState::Instance());
	//}
	//else
	//{
	//	static float a = 0.0f;
	//	a += 2.0f * TheTimer::Instance()->GetDt();
	//	float alpha = sin(a) + 1.0f;
	//	t.Update("Click to start . . .");
	//	t.Translate(D3DXVECTOR3(0.0f, 0.0f, 0.0f));
	//	alpha *= 0.4f;
	//	t.SetColour(D3DXVECTOR4(0.0f, 1.0f, 0.89411f, alpha));
	//
	//	//if (t.Intersected(m_convertedMousePos))
	//	//{
	//	//	t.Update("hit");
	//	//}

	//	t.Draw();
	//}
	
}

void TitleScreenState::Update()
{
}

void TitleScreenState::HostAndPlay()
{
	// server button
	
	m_text.Update(m_port);
	m_text.Translate(D3DXVECTOR3(m_portText.size() * m_spacing, 0.3f, 0.0f));
	m_text.SetColour(D3DXVECTOR4(m_col.x, m_col.y, m_col.z, m_alpha));
	m_text.Draw();
	
	std::string spaces;
	m_text.Update(m_portText);
	m_text.Translate(D3DXVECTOR3(m_port.size() * -m_spacing, 0.3f, 0.0f));
	m_text.SetColour(D3DXVECTOR4(m_col.x, m_col.y, m_col.z, m_alpha));
	m_text.Draw();
	m_text.Update(m_portText + m_port);
	if (m_text.Intersected(m_convertedMousePos))
	{
		if (m_mouseDown)
		{
			// blink cursor and look for key presses
			m_canEditPort = true;
			m_mouseDown = false;
		}
		if (!m_canEditPort)
		{
			int total = m_portText.size() + m_port.size();
			for (int i = 0; i != total; i++)
			{
				spaces += " ";
			}
			
			m_text.Update("<" + spaces + ">");
			m_text.Translate(D3DXVECTOR3(0.0f, 0.3f, 0.0f));


			m_text.Draw();
		}
	}

	if (m_canEditPort)
	{
		static float blinkTimer = 0.0f;
		static float alpha = 0.0f;
		blinkTimer += TheTimer::Instance()->GetDt();

		if (blinkTimer >= 0.5f)
		{
			if (alpha == 0.0f)
			{
				alpha = 1.0f;
			}
			else
			{
				alpha = 0.0f;
			}

			blinkTimer = 0.0f;
		}

		spaces = " ";
		int total = m_portText.size() + m_port.size();
		for (int i = 0; i != total; i++)
		{
			spaces += " ";
		}
		m_text.Update(spaces + "|");
		m_text.Translate(D3DXVECTOR3(0.0f, 0.3f, 0.0f));
		m_text.SetColour(D3DXVECTOR4(m_col.x, m_col.y, m_col.z, alpha));
		m_text.Draw();
	}
	
	//play
	m_text.Update("Play");
	m_text.Translate(D3DXVECTOR3(0.0f, 0.1f, 0.0f));
	m_text.SetColour(D3DXVECTOR4(m_col.x, m_col.y, m_col.z, m_alpha));
	m_text.Draw();
	if (m_text.Intersected(m_convertedMousePos))
	{
		m_text.SetColour(D3DXVECTOR4(m_col.x, m_col.y, m_col.z, 0.0f));
		m_text.Update("<      >");
		m_text.Draw();
		if (m_mouseDown)
		{
			m_curState = CREATING_SERVER;
			m_canEditPort = false;
			m_canEditServer = false;
			m_mouseDown = false;

			// create server and go to play state

		}
	}



	// back
	m_text.Update("Back");
	m_text.Translate(D3DXVECTOR3(0.0f, -0.1f, 0.0f));
	m_text.SetColour(D3DXVECTOR4(m_col.x, m_col.y, m_col.z, m_alpha));
	m_text.Draw();
	if (m_text.Intersected(m_convertedMousePos))
	{
		m_text.SetColour(D3DXVECTOR4(m_col.x, m_col.y, m_col.z, 0.0f));
		m_text.Update("<      >");
		m_text.Draw();
		if (m_mouseDown)
		{
			m_curState = MAIN;
			m_canEditPort = false;
			m_mouseDown = false;
		}
	}
}

void TitleScreenState::Join()
{
	static float blinkTimer = 0.0f;
	static float alpha = 0.0f;
	blinkTimer += TheTimer::Instance()->GetDt();

	if (blinkTimer >= 0.5f)
	{
		if (alpha == 0.0f)
		{
			alpha = 1.0f;
		}
		else
		{
			alpha = 0.0f;
		}

		blinkTimer = 0.0f;
	}

	// server ip

	m_text.Update(m_serverIP);
	m_text.Translate(D3DXVECTOR3(m_serverText.size() * m_spacing, 0.3f, 0.0f));
	m_text.SetColour(D3DXVECTOR4(m_col.x, m_col.y, m_col.z, m_alpha));
	m_text.Draw();

	m_text.Update(m_serverText);
	m_text.Translate(D3DXVECTOR3(m_serverIP.size() * -m_spacing, 0.3f, 0.0f));
	m_text.SetColour(D3DXVECTOR4(m_col.x, m_col.y, m_col.z, m_alpha));
	m_text.Draw();
	m_text.Update(m_serverText + m_serverIP);

	if (m_text.Intersected(m_convertedMousePos))
	{
		if (m_mouseDown)
		{
			// blink cursor and look for key presses
			m_canEditServer = true;
			m_canEditPort = false;
			m_mouseDown = false;
		}
		if (!m_canEditServer)
		{
			std::string spaces = " ";
			int total = m_serverIP.size() + m_serverText.size();
			for (int i = 0; i != total; i++)
			{
				spaces += " ";
			}
			
			m_text.Update("<" + spaces + ">");
			m_text.Translate(D3DXVECTOR3(0.0f, 0.3f, 0.0f));
			m_text.Draw();
		}
	}
	// server blinker
	if (m_canEditServer)
	{
		std::string spaces = " ";
		int total = m_serverText.size() + m_serverIP.size();
		for (int i = 0; i != total; i++)
		{
			spaces += " ";
		}
		m_text.Update(spaces + "|");
		m_text.Translate(D3DXVECTOR3(0.0f, 0.3f, 0.0f));
		m_text.SetColour(D3DXVECTOR4(m_col.x, m_col.y, m_col.z, alpha));
		m_text.Draw();
	}

	// port
	
	m_text.Update(m_port);
	m_text.Translate(D3DXVECTOR3(m_portText.size() * m_spacing, 0.1f, 0.0f));
	m_text.SetColour(D3DXVECTOR4(m_col.x, m_col.y, m_col.z, m_alpha));
	m_text.Draw();
	
	m_text.Update(m_portText);
	m_text.Translate(D3DXVECTOR3(m_port.size() * -m_spacing, 0.1f, 0.0f));
	m_text.SetColour(D3DXVECTOR4(m_col.x, m_col.y, m_col.z, m_alpha));
	m_text.Draw();
	m_text.Update(m_portText + m_port);
	if (m_text.Intersected(m_convertedMousePos))
	{
		if (m_mouseDown)
		{
			// blink cursor and look for key presses
			m_canEditPort = true;
			m_canEditServer = false;
			m_mouseDown = false;
		}
		if (!m_canEditPort)
		{
			std::string spaces = " ";
			int total = m_port.size() + m_portText.size();
			for (int i = 0; i != total; i++)
			{
				spaces += " ";
			}
			
			m_text.Update("<" + spaces + ">");
			m_text.Translate(D3DXVECTOR3(0.0f, 0.1f, 0.0f));


			m_text.Draw();
		}
	}
	// port blinker
	if (m_canEditPort)
	{
		std::string spaces = " ";
		int total = m_portText.size() + m_port.size();
		for (int i = 0; i != total; i++)
		{
			spaces += " ";
		}
		m_text.Update(spaces + "|");
		m_text.Translate(D3DXVECTOR3(0.0f, 0.1f, 0.0f));
		m_text.SetColour(D3DXVECTOR4(m_col.x, m_col.y, m_col.z, alpha));
		m_text.Draw();
	}

	// play
	
	m_text.Update("Play");
	m_text.Translate(D3DXVECTOR3(0.0f, -0.1f, 0.0f));
	m_text.SetColour(D3DXVECTOR4(m_col.x, m_col.y, m_col.z, m_alpha));
	m_text.Draw();
	if (m_text.Intersected(m_convertedMousePos))
	{
		m_text.SetColour(D3DXVECTOR4(m_col.x, m_col.y, m_col.z, 0.0f));
		m_text.Update("<      >");
		m_text.Draw();
		if (m_mouseDown)
		{
			m_curState = CONNECTING_TO_SERVER;
			m_canEditPort = false;
			m_canEditServer = false;
			m_mouseDown = false;

			// connec to host and play
		}
	}


	

	// back
	m_text.Update("Back");
	m_text.Translate(D3DXVECTOR3(0.0f, -0.3f, 0.0f));
	m_text.SetColour(D3DXVECTOR4(m_col.x, m_col.y, m_col.z, m_alpha));
	m_text.Draw();
	if (m_text.Intersected(m_convertedMousePos))
	{
		m_text.SetColour(D3DXVECTOR4(m_col.x, m_col.y, m_col.z, 0.0f));
		m_text.Update("<      >");
		m_text.Draw();
		if (m_mouseDown)
		{
			m_curState = MAIN;
			m_canEditPort = false;
			m_canEditServer = false;
			m_mouseDown = false;
		}
	}
}
void TitleScreenState::ConnectToServer()
{
	static float time = 0.0f;
	
	static bool connected = TheClientManager::Instance()->Open(m_serverIP, ToInt(m_port));

	if (connected)
	{
		m_text.Update("Connected");
		m_text.Translate(D3DXVECTOR3(0.0f, 0.0f, 0.0f));
		m_text.SetColour(D3DXVECTOR4(m_col.x, m_col.y, m_col.z, m_alpha));
		m_text.Draw();
		if (m_text.Intersected(m_convertedMousePos))
		{
			m_text.SetColour(D3DXVECTOR4(m_col.x, m_col.y, m_col.z, 0.0f));
			m_text.Update("<      >");
			m_text.Draw();
			if (m_mouseDown)
			{
				m_curState = MAIN;
				m_canEditPort = false;
				m_canEditServer = false;
				m_mouseDown = false;
			}
		}
	}
	else
	{
		m_text.Update("Failed to Connect");
		m_text.Translate(D3DXVECTOR3(0.0f, 0.0f, 0.0f));
		m_text.SetColour(D3DXVECTOR4(m_col.x, m_col.y, m_col.z, m_alpha));
		m_text.Draw();
		m_curState = MAIN;
	}

	time += TheTimer::Instance()->GetDt();
	// test - send game message to server
	if (connected)
	{
		//SocketMessage sm;
		//GMCreatePlayer cp;
		//cp.Write(&sm);
		//SendGameMessage(cp, &TheClientManager::Instance()->GetSocket());

		// start msg recv thread
		MessageRecvThread* mrt = new MessageRecvThread(&TheClientManager::Instance()->GetSocket());
		mrt->Start();
		TheGame::Instance()->SetGameState(TheInfoState::Instance());
	}

	if (time >= 3.0f)
	{
		time = 0.0f;
		m_curState = MAIN;
		// go to play state
	}
}

void TitleScreenState::CreateServer()
{
	static bool callOnce = true;
	if (callOnce)
	{
		callOnce = false;
		int port = ToInt(m_port);
		AcceptConThread* act = new AcceptConThread(port);
		act->Start();
		CheckPingThread* cpt = new CheckPingThread();
		cpt->Start();
	}

	m_text.Update("Server Created");
	m_text.Translate(D3DXVECTOR3(0.0f, 0.0f, 0.0f));
	m_text.SetColour(D3DXVECTOR4(m_col.x, m_col.y, m_col.z, m_alpha));
	m_text.Draw();
	static float time = 0.0f;
	time += TheTimer::Instance()->GetDt();
	if (time >= 3.0f)
	{
		time = 0.0f;
		m_curState = MAIN;
		// go to play state
		m_serverIP = "localhost";
		static bool connectedToServer = TheClientManager::Instance()->Open(m_serverIP, ToInt(m_port));
		if (connectedToServer)
		{
			MessageRecvThread* mrt = new MessageRecvThread(&TheClientManager::Instance()->GetSocket());
			mrt->Start();
			TheGame::Instance()->SetGameState(TheInfoState::Instance());
			std::cout << "Client connected" << std::endl;
		}
	}
}


void TitleScreenState::OnActivated()
{
	TheEventPoller::Instance()->AddHandler(this);
	m_mouseDown = false;
}
void TitleScreenState::OnDeactivated()
{
	TheEventPoller::Instance()->RemoveHandler(this);
	m_mouseDown = false;
}

void TitleScreenState::OnKeyDownEvent(const WPARAM& event)
{			
	char c = MapVirtualKey(event, MAPVK_VK_TO_CHAR);
	
	if (m_canEditPort)
	{
		if (event == VK_RETURN)
		{
			m_canEditPort = false;
			// start server etc
		}
		else if (event == VK_BACK)
		{
			if (!m_port.empty())
			{
				m_port = std::string(m_port.begin(), m_port.end() - 1);
			}
		}
		
		else if (c >= 48 && c <= 57)
		{
			// check if it's within number range
			m_port += c;			
		}
	}
	else if (m_canEditServer)
	{
		if (event == VK_RETURN)
		{
			m_canEditServer = false;
			// start server etc
		}
		else if (event == VK_BACK)
		{
			if (!m_serverIP.empty())
			{
				m_serverIP = std::string(m_serverIP.begin(), m_serverIP.end() - 1);
			}
		}
		
		else if ((c >= 48 && c <= 57) || c == '.')
		{
			// check if it's within number range
			m_serverIP += c;			
		}
	}
}

void TitleScreenState::OnKeyUpEvent(const WPARAM& event)
{	
}

void TitleScreenState::OnMouseMotionEvent(const LPARAM& event)
{
	int x = LOWORD(event);
	int y = HIWORD(event);
	m_mousePos = D3DXVECTOR2(float(x), float(y));
	m_convertedMousePos.x = (m_mousePos.x - (m_screenSize.x * 0.5f)) / (m_screenSize.x * 0.5f);
	m_convertedMousePos.y = (m_mousePos.y - (m_screenSize.y * 0.5f)) / (m_screenSize.y * 0.5f) * -1.0f;
}

void TitleScreenState::OnMouseButtonDownEvent(const MSG& event)
{
	m_mouseDown = true;
}

void TitleScreenState::OnMouseButtonUpEvent(const MSG& event)
{
	m_mouseDown = false;
}